﻿using System;
using System.Data.Services.Client;
using System.Globalization;
using System.Net;
using System.Text;
using System.Windows;
using Tfs.OnTheRoad.Commands;
using Tfs.OnTheRoad.Helpers;
namespace Tfs.OnTheRoad.ViewModel
{
    /// <summary>
    /// Base List ViewModel
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public abstract class BaseListViewModel<T> : BaseViewModel, Tfs.OnTheRoad.ViewModel.IBaseListViewModel
    {
        public override void Refresh()
        {
            this.LoadData();
        }

        protected override void SaveState(Microsoft.Phone.Controls.PhoneApplicationPage page)
        {
            var viewModel = page.DataContext as IBaseListViewModel;
            if (viewModel != null)
            {
                string currentPageNumerName = viewModel.ToString() + "CurrentPageNumber";
                if (page.State.ContainsKey(currentPageNumerName))
                    page.State.Remove(currentPageNumerName);
                page.State.Add(currentPageNumerName, viewModel.PageNumber);
            }
        }

        protected override void RestoreState(Microsoft.Phone.Controls.PhoneApplicationPage page)
        {
            var viewModel = page.DataContext as IBaseListViewModel;
            if (viewModel != null)
            {
                string currentPageNumerName = viewModel.ToString() + "CurrentPageNumber";
                if (page.State.ContainsKey(currentPageNumerName))
                    viewModel.PageNumber = (int)page.State[currentPageNumerName];
            }
        }

        public bool Loaded { get; set; }

        public LoadMoreItemsCommand LoadMoreItems
        {
            get;
            private set;
        }

        private int currentPage = 0;
        private bool searching = false;
        private bool hasResults = false;
        private string query = string.Empty;
        private string noResultsFoundMessage = string.Empty;

        public BaseListViewModel()
        {
            this.Items = new DataServiceCollection<T>(App.CreateTfsDataServiceContext());
            this.Items.LoadCompleted += this.ItemsLoadCompleted;
            LoadMoreItems = new LoadMoreItemsCommand(this);
            Loaded = false;
        }

        /// <summary>
        ///Called when the Profile has changed
        /// </summary>
        public void RecreateContext()
        {
            if(this.Items!=null)
                this.Items.LoadCompleted -= this.ItemsLoadCompleted;
            this.Items = new DataServiceCollection<T>(App.CreateTfsDataServiceContext());
            this.Items.LoadCompleted += this.ItemsLoadCompleted;
            LoadMoreItems = new LoadMoreItemsCommand(this);
            Loaded = false;
            this.RaisePropertyChanged("Items");
        }

        public BaseListViewModel(string path)
            : this()
        {
            this.Path = path;            
        }

        private string _orderBy;

        public string OrderBy
        {
            get { return _orderBy; }
            set
            {
                _orderBy = value;
                this.RaisePropertyChanged("OrderBy");
            }
        }
        


        public DataServiceCollection<T> Items { get; set; }

        public int PageNumber { get; set; }

        public string Query
        {
            get
            {
                return this.query;
            }
            set
            {
                this.query = value;
                this.RaisePropertyChanged("Query");
            }
        }

        public bool IsSearching
        {
            get
            {
                return this.searching;
            }
            set
            {
                this.searching = value;
                this.RaisePropertyChanged("IsSearching");
            }
        }

        public bool HasResults
        {
            get
            {
                return this.hasResults;
            }
            set
            {
                this.hasResults = value;
                this.RaisePropertyChanged("HasResults");
            }
        }

        public bool HasContinuation
        {
            get
            {
                return this.Items.Continuation != null;
            }
        }

        public bool LoadMoreResultsVisible
        {
            get
            {
                return this.HasContinuation && !this.IsSearching;
            }
        }

        public string NoResultsFoundMessage
        {
            get
            {
                return this.noResultsFoundMessage;
            }
            set
            {
                this.noResultsFoundMessage = value;
                this.RaisePropertyChanged("NoResultsFoundMessage");
            }
        }

        protected string Path { get; set; }

        public virtual void LoadData()
        {
            this.IsSearching = true;

            var requestUri = BuildRequestUri(this.GetEntityCollectionName(), this.Path, this.Query, this.OrderBy);

            this.Items.Clear();
            this.Items.LoadAsync(requestUri);
        }

        public void LoadNextPage()
        {
            if (this.HasContinuation && !this.IsSearching)
            {
                this.IsSearching = true;
                this.Items.LoadNextPartialSetAsync();
            }
        }

        public abstract string GetNoResultsFoundMessage();

        public abstract string GetEntityCollectionName();

        private static Uri BuildRequestUri(string entityCollectionName, string path, string filter, string orderBy)
        {
            var sb = new StringBuilder().Append(App.SettingsViewModel.FullAddress.TrimEnd('/'));

            if (!string.IsNullOrEmpty(path))
            {
                sb.AppendFormat(CultureInfo.InvariantCulture, "/{0}/{1}", path, entityCollectionName);
            }
            else
            {
                sb.AppendFormat(CultureInfo.InvariantCulture, "/{0}",entityCollectionName);
            }
            bool hasOrderBy = !string.IsNullOrEmpty(orderBy);
            if (!string.IsNullOrEmpty(orderBy))
            {
                sb = sb.AppendFormat(CultureInfo.InvariantCulture, "?$orderby={0}", HttpUtility.UrlEncode(orderBy));
            }

            if (!string.IsNullOrEmpty(filter))
            {
                string concatChar = "?";
                if (hasOrderBy)
                    concatChar = "&";

                sb = sb.AppendFormat(CultureInfo.InvariantCulture, "{0}$filter={1}",concatChar, HttpUtility.UrlEncode(filter));
            }
            return new Uri(sb.ToString(), UriKind.Absolute);
        }

        private void ItemsLoadCompleted(object sender, LoadCompletedEventArgs e)
        {
            if (e.Cancelled)
            {
                this.DispatchResult(true, "The operation has been cancelled");
            }
            else if (e.Error != null)
            {
                var message = e.Error.Message;
                Exception dataServiceException;
                if (!System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable())
                    message = "Unable to connect. Data/Wi-Fi connection not available.";
                else if (DataServiceExceptionHelper.TryParse(e.Error, out dataServiceException))
                {
                    message = dataServiceException.Message;
                }
                else if ((e.Error.InnerException != null) && !string.IsNullOrEmpty(e.Error.InnerException.Message))
                {
                    if(string.Compare(e.Error.InnerException.Message,"NotFound",StringComparison.OrdinalIgnoreCase)==0)
                        message = string.Format("The address '{0}' could not be found.",App.SettingsViewModel.FullAddress);
                    else
                        message = e.Error.InnerException.Message;
                }

                this.DispatchResult(true, message);
            }
            else
            {
                this.currentPage++;

                if (this.PageNumber < this.currentPage)
                {
                    this.PageNumber = this.currentPage;
                }

                if (this.HasContinuation && this.PageNumber > this.currentPage)
                {
                    this.Items.LoadNextPartialSetAsync();
                }

                Loaded = true;
                this.DispatchResult(false);
            }
        }

        private void DispatchResult(bool hasErrors, string errorMessage = null)
        {
            Deployment.Current.Dispatcher.BeginInvoke(() =>
            {
                this.HasResults = false;
                this.IsSearching = false;

                if (!hasErrors)
                {
                    if ((this.Items == null) || (this.Items.Count == 0))
                    {
                        this.NoResultsFoundMessage = this.GetNoResultsFoundMessage();
                    }
                    else
                    {
                        this.HasResults = true;
                    }
                }
                else
                {
                    this.NoResultsFoundMessage = errorMessage;
                }

                this.RaisePropertyChanged("LoadMoreResultsVisible");
            });
        }
    }
}
